/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
package robocup.component.tactics;

import java.util.LinkedList;

import robocup.component.Prophet;
import robocup.component.RobocupAgent;
import robocup.component.SConf;
import robocup.component.StateTactic;
import robocup.component.WorldModel;
import robocup.component.worldobjects.Ball;
import robocup.component.worldobjects.Player;

/**
 * This class contains all of the players states and offers methods for 
 * calculating the best state.
 */
public class StateEvaluation {

	/**
   * all states 
	 */
  private LinkedList<AbstractState> permanentStates;

	/**
   * the world. 
	 */
  private WorldModel world;

  /**
   * the prophet.
   */
  private Prophet prophet;

  /**
   * the {@link StateTactic}.
   */
	private StateTactic parent;

  /**
   * the player capable of all the states.
   */
	private Player player;

  /**
   * Ref. to the ball
   */
	private Ball ball;

  /**
   * the assessment of the max. state
   */
	private double maxStateAssessment = 0.0;

  /**
   * all states with a true precondition in a given cycle.
   */
	private LinkedList<AbstractState> possibleStates = new LinkedList<AbstractState>();

	/**
	 * This class is the basic state-selecting component. It evaluates all
	 * possible states and selects the 'best' for the given agent thereafter.
	 * 
	 * StateEvaluation must be initalized: It refers to the StateTactic
	 * (neccessary?) and to the RobocupClient, which is used to send actions!
	 * 
	 * @param parent -
	 *            the StateTactic holds the evaluation
	 * @param client -
	 *            the agent object
   *            
   * @return the StateEvaluation
	 */
	public StateEvaluation(StateTactic parent, RobocupAgent client) {

		this.parent = parent;
		this.prophet = parent.getProphet();
		this.permanentStates = new LinkedList<AbstractState>();

		if (client != null) {
			this.world = client.getWorld();
			this.player = world.getSelfRef();
		}
	}

	/**
	 * adds a State to the State Evaluation.
   * (used for loading all states from the player's *.conf file)
	 * 
	 * @param state - the state
	 */
	public void addState(AbstractState state) {

		if (!this.permanentStates.contains(state))
			this.permanentStates.add(state);
	}

	/**
	 * calculates the state with the max assessment and stores the result to 
   * <code>#maxStateAssessment</code> and <code>#possibleStates</code>
	 * 
	 * @param p -
	 *            player
	 * @param b -
	 *            ball
	 */
	public void calculateBestState(Player p, Ball b) {

		this.player = p;
		this.ball = b;
		this.possibleStates.clear();
		this.maxStateAssessment = 0.0;

		for (AbstractState state : this.permanentStates) {
			state.reset();

			if (state.preCondition()) {

				this.maxStateAssessment = Math.max(this.maxStateAssessment,
						state.getStateAssessment());
				this.addPossibleStateToList(state);
			}
		}
	}

	/**
	 * adds a state to the possible states. the possible state list remains
	 * ordered.
	 * 
	 * @param state -
	 *            the state to add
	 */
	private void addPossibleStateToList(AbstractState state) {

		double assessment = state.getStateAssessment();

		int i = 0;
		for (; i < this.possibleStates.size(); i++) {
			if (this.possibleStates.get(i).getStateAssessment() < assessment) {
				break;
			}
		}
		this.possibleStates.add(i, state);
	}

	/**
	 * @return all the possible states.
	 */
	public LinkedList<AbstractState> getPossibleStates() {

		return this.possibleStates;
	}

	/**
	 * the best state. (the state with the maximum assessment)
	 * 
	 * @return
	 */
	public AbstractState getBestState() {

		if (this.possibleStates.size() == 0) {
			return null;
		}
		return this.possibleStates.get(0);
	}

	/**
	 * ************** SIMPLE GETTER/SETTER ********************
	 */

  /**
   * @return the StateTactic.
   */
	public StateTactic getParent() {

		return this.parent;
	}

  /**
   * @return the {@link SConf}
   */
	public SConf getSConf() {

		return SConf.getInstance();
	}

  /**
   * @return the world
   */
	public WorldModel getWorld() {

		return this.world;
	}

	/**
	 * @return Returns the prophet.
	 */
	public Prophet getProphet() {

		return this.prophet;
	}

	/**
	 * @return Returns the player.
	 */
	public Player getPlayer() {

		return this.player;
	}

	/**
	 * @param player
	 *            The player to set.
	 */
	public void setPlayer(Player player) {

		this.player = player;
	}

	/**
	 * @return Returns the ball.
	 */
	public Ball getBall() {

		return this.ball;
	}

	/**
	 * @param ball
	 *            The ball to set.
	 */
	public void setBall(Ball ball) {

		this.ball = ball;
	}

	/**
	 * @return Returns the maxStateAssessment.
	 */
	public double getMaxStateAssessment() {

		return this.maxStateAssessment;
	}
}
